package com.common.util;

import cn.hutool.core.util.ReflectUtil;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 构建树结构工具类
 */
public class TreeUtil {

    /**
     * 根据反射获取属性值
     * @param t 实体对象
     * @param fieldName 属性名称
     */
    private static<T> Object getFieldValue(T t,String fieldName){
        Field field = ReflectUtil.getField(t.getClass(), fieldName);
        return ReflectUtil.getFieldValue(t, field);
    }

    /**
     * 获取树结构（parentId是固定值，比如它是根目录，值为0或ROOT）
     */
    public static<T> List<T> buildTreeIsRoot(List<T> list,String parentId) {
        List<T> root = buildTree(list, parentId);
        getChild(root, list);
        return root;
    }

    /**
     * 获取树结构（parentId值不确定）
     */
    public static<T> List<T> buildTreeNotRoot(List<T> list) {
        List<T> sources = new ArrayList<>(list);
        List<T> result = new ArrayList<>();
        for (T t : sources) {
            String parentId = (String)getFieldValue(t,"parentId");
            List<T> root = buildTree(list, parentId);
            getChild(root, list);
            result.addAll(root);
        }
        return result;
    }

    /**
     * 获取树结构
     * @param list 数据
     * @param pId 父级id
     */
    public static<T> List<T> buildTree(List<T> list,String pId){
        List<T> root= new ArrayList<>();
        Iterator<T> it = list.iterator();
        while (it.hasNext()) {
            T t = it.next();
            String parentId = (String)getFieldValue(t,"parentId");
            if (parentId.equals(pId)) {
                root.add(t);
                it.remove();
            }
        }
        return root;
    }

    /**
     * 递归子节点
     */
    public static<T> void getChild(List<T> root,List<T> list){
        try {
            for (T nav : root) {
                String id = (String)getFieldValue(nav,"id");
                List<T> childList = buildTree(list, id);
                getChild(childList, list);
                Field child = ReflectUtil.getField(nav.getClass(), "children");
                child.set(nav,childList);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

}
